package server

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"longmen/server/config/global"
	"longmen/server/pkg/common/helper/const"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/db/mysql/db_guess"
	"longmen/server/pkg/db/mysql/db_live"
	"longmen/server/pkg/db/mysql/models/models_guess"
	"longmen/server/pkg/db/redis/cache"
	pb "longmen/server/pkg/protobuf"
	"time"
)

func (s *Server) CreateGuess(ctx context.Context, req *pb.CreateGuessReq) (*pb.CreateGuessResp, error) {
	fName := "CreateGuess"
	var n int64
	bHost, err := db_guess.CheckAnchorCanHostGuess(int(req.AnchorId))
	if err != nil {
		return nil, global.LogAndErrorf("%s%v", util.Convert(fName), err.Error())
	}
	if !bHost {
		return nil, errors.New(_const.GUESS_ERR_ANCHOR_CANNOT)
	}
	q, err := db_guess.CheckAnchorQuestion(int(req.AnchorId), int(req.QId))
	if err != nil || q == nil {
		return nil, errors.New(_const.GUESS_ERR_BAD_QUESTION)
	} else if q.Status != _const.QUESTION_STATUS_READY {
		return nil, errors.New(_const.GUESS_ERR_BAD_QUESTION_STATUS)
	}
	if req.Duration < 10 || req.Duration > 1440*15 { //时间最小设为10分钟最大是15天
		return nil, errors.New(_const.GUESS_ERR_BAD_DURATION)
	}
	aCate, _ := db_live.GetLiveCategory(map[string]interface{}{"id": req.CategoryId})
	if aCate == nil || aCate.Id == 0 {
		return nil, errors.New(_const.GUESS_ERR_CATE_ID)
	}
	liveInfo, _ := db_live.GetLiveParam(map[string]interface{}{"anchorid": req.AnchorId})
	if liveInfo.Liveid != int64(req.LiveId) {
		return nil, errors.New(_const.GUESS_ERR_BAD_LIVE_ID)
	}
	n = 0
	err = db_guess.CountGuessAnyParam(&models_guess.Guess{}, &n,
		map[string]interface{}{"q_id": req.QId, "live_id": req.LiveId}, "checkGuessLive", "", 0, 0)
	if n != 0 {
		return nil, errors.New(_const.GUESS_ERR_USED_QUESTION)
	}
	err = db_guess.CountGuessAnyParam(&models_guess.Guess{}, &n,
		map[string]interface{}{"live_id": req.LiveId}, "checkGuessLive", "", 0, 0)
	if n >= 20 { //限制一场直播最多只能开20场竞猜
		return nil, errors.New(_const.GUESS_ERR_TOO_MANY_GUESS)
	}
	guessGame := &models_guess.Guess{
		CreateTime: time.Now(),
		QId:        int(req.QId),
		AnchorId:   int(req.AnchorId),
		CategoryId: int(req.CategoryId),
		LiveId:     req.LiveId,
		EndTime:    time.Now().Unix() + int64(req.Duration)*60,
		MinBet:     q.MinBet,
		ItemNum:    q.ItemNum,
		Status:     _const.GUESS_STATUS_OPEN,

		Odds:        "", //赔率待封盘时才有
		TotalAmount: "",
		PeopleNum:   "",
		TotalPeople: 0,
		Result:      0, //未有结果
		Content:     q.Content,
		Title:       q.Title,

		LiveTitle: liveInfo.Title,

		MatchTitle: q.MatchTitle,
		Comp:       q.Comp,
	}
	id, err := db_guess.GuessInsertAny(guessGame, "InsertGuess")
	if err != nil {
		return nil, global.LogAndErrorf("%s%v", util.Convert(fName), err.Error())
	}
	if id == 0 {
		return nil, fmt.Errorf(_const.GUESS_ERR_UNKNOWN)
	}
	err = cache.PrepareMsgUpdateGuessStatus(guessGame.LiveId, false)
	if err != nil {
		global.Log.Errorf("%s", err.Error())
	}
	return &pb.CreateGuessResp{
		GId: int32(id),
		Msg: "ok",
	}, nil
}

// 把状态更改为封盘
func (s *Server) CloseGuess(ctx context.Context, req *pb.CloseGuessReq) (*pb.CloseGuessResp, error) {
	if req.GId == 0 {
		return nil, errors.New("缺少g_id")
	}
	o, err := cache.GetGuessInfo(int(req.GId), 0, false)
	var sMsg = "ok"
	if err != nil {
		return nil, errors.New("该期竞猜无效")
	}
	if o.Status != _const.GUESS_STATUS_OPEN {
		return nil, fmt.Errorf("只有open的场次才能封盘")
	}
	oGuess := &models_guess.Guess{
		Id:        int(req.GId),
		Status:    _const.GUESS_STATUS_CLOSED,
		PayStatus: _const.GUESS_PAY_NOT_PAID,
	}
	err = db_guess.UpdateGuessAnyWithId(nil, []string{"status", "pay_status"}, oGuess, "CloseGuess")
	if err != nil {
		return nil, err
	}
	global.Log.Debugf("close models_guess and refresh:%+v", o)
	cache.PrepareMsgUpdateGuessStatus(o.LiveId, true) //封盘要刷新一下
	cache.WriteOdds(_const.GUESS_STATUS_CLOSED)
	return &pb.CloseGuessResp{
		Msg: sMsg,
	}, nil
}

// 把状态改为取消，所有投注退掉
func (s *Server) CancelGuess(ctx context.Context, req *pb.CancelGuessReq) (*pb.CancelGuessResp, error) {
	if req.GId == 0 {
		return nil, errors.New("缺少g_id")
	}
	o, err := cache.GetGuessInfo(int(req.GId), 0, false)
	if err != nil {
		return nil, errors.New("该期竞猜无效")
	}
	iNextStatus := _const.GUESS_STATUS_CANCELED
	if o.Status == _const.GUESS_STATUS_SETTLED {
		iNextStatus = _const.GUESS_STATUS_SETTLED_CANCELED
	} else if o.Status != _const.GUESS_STATUS_OPEN {
		return nil, errors.New("只有已结算或open的场次才能取消")
	}
	oGuess := &models_guess.Guess{
		Id:        int(req.GId),
		Status:    iNextStatus,
		PayStatus: _const.GUESS_PAY_NOT_PAID,
	}
	err = db_guess.UpdateGuessAnyWithId(nil, []string{"status", "pay_status"}, oGuess, "CancelGuess")
	if err != nil {
		return nil, err
	}
	cache.PrepareMsgUpdateGuessStatus(o.LiveId, true) //取消刷新一下

	return &pb.CancelGuessResp{
		Msg: "ok",
	}, nil
}

// 填奖
func (s *Server) SettleGuess(ctx context.Context, req *pb.SettleGuessReq) (*pb.SettleGuessResp, error) {
	if req.GId == 0 {
		return nil, errors.New("缺少g_id")
	}
	oInfo, err := cache.GetGuessInfo(int(req.GId), 0, true)
	if err != nil || oInfo.GId == 0 {
		return nil, errors.New("该期竞猜无效")
	}
	if oInfo.Status != _const.GUESS_STATUS_CLOSED {
		return nil, errors.New("只有正常结束后的竞猜才能开奖")
	}
	if int(req.Result) > oInfo.ItemNum {
		return nil, errors.New("无效的开奖项")
	}
	oGuess := &models_guess.Guess{
		Id:         int(req.GId),
		Result:     int(req.Result),
		Status:     _const.GUESS_STATUS_SETTLED,
		PayStatus:  _const.GUESS_PAY_NOT_PAID,
		SettleTime: time.Now(),
	}
	err = db_guess.UpdateGuessAnyWithId(nil, []string{"status", "result", "settle_time", "pay_status"}, oGuess, "SettleGuess")
	if err != nil {
		return nil, err
	}
	cache.PrepareMsgUpdateGuessStatus(oInfo.LiveId, true)
	cache.WriteOdds(_const.GUESS_STATUS_SETTLED)
	return &pb.SettleGuessResp{
		Msg: "ok",
	}, nil
}

// 得一场竞猜信息
func (s *Server) GetGuess(ctx context.Context, req *pb.GetGuessReq) (*pb.GetGuessResp, error) {
	o, err := cache.GetGuessInfo(int(req.GId), 0, false)
	if err != nil {
		return nil, err
	}
	sPeople, _ := json.Marshal(o.PeopleNumList)
	sOdds, _ := json.Marshal(o.OddsList)
	sAmount, _ := json.Marshal(o.AmountList)
	var sum int32
	sum = 0
	for _, v := range o.AmountList {
		sum += int32(v)
	}
	return &pb.GetGuessResp{
		GId:         req.GId,
		QId:         int32(o.QId),
		LiveId:      o.LiveId,
		EndTime:     time.Unix(o.EndTime, 0).Format("2006-01-02 15:04:05"),
		MinBet:      int32(o.MinBet),
		PeopleNum:   string(sPeople),
		Odds:        string(sOdds),
		TotalAmount: string(sAmount),
		ItemNum:     int32(o.ItemNum),
		Pot:         sum,
		Content:     o.Content,
		Title:       o.Title,
	}, nil
}

// 得一组竞猜信息
func (s *Server) GetGuessList(ctx context.Context, req *pb.GetGuessListReq) (*pb.GetGuessListResp, error) {
	var n int64
	var bLiveRoom = false
	oGuessList := make([]*models_guess.Guess, 0, 0)
	mQuery := make(map[string]interface{}, 0)

	if req.AnchorId > 0 {
		(mQuery)["anchor_id"] = req.AnchorId
	}
	if req.LiveId > 0 {
		(mQuery)["live_id"] = req.LiveId
		bLiveRoom = true
	}
	if req.QId > 0 {
		(mQuery)["q_id"] = req.QId
	}
	if len(req.TEnd) != 0 && len(req.TStart) > 0 {
		if time2.StrToUnix(req.TEnd) == 0 {
			return nil, fmt.Errorf("时间格式有误")
		}
		if time2.StrToUnix(req.TStart) == 0 {
			return nil, fmt.Errorf("时间格式有误")
		}
		mQuery["create_time"] = map[string]interface{}{"between": []interface{}{req.TStart, req.TEnd}}
	}

	if len(mQuery) == 0 {
		return nil, fmt.Errorf("参数有误")
	}
	err := db_guess.GetGuessAnyListParam(&models_guess.Guess{}, &oGuessList, mQuery,
		"GetGuessList", "", int(req.Page), int(req.Size))
	if err != nil {
		return nil, err
	}
	n = 0
	slice := make([]*pb.GetGuessResp, 0)
	if len(oGuessList) > 0 {
		err = db_guess.CountGuessAnyParam(&models_guess.Guess{}, &n, mQuery, "GetGCount", "", 0, 0)
		if err != nil {
			return nil, err
		}

		if bLiveRoom {
			cache.PrepareMsgUpdateGuessStatus(req.LiveId, false)
		}
		for _, v := range oGuessList {
			if v.Id == 0 {
				continue
			}
			sTotalAmount := []byte(v.TotalAmount)
			sPeopleList := []byte(v.PeopleNum)
			sOddsList := []byte(v.Odds)
			if v.Status == _const.GUESS_STATUS_OPEN { //只有open的才需要查缓存
				gInfo, err := cache.GetGuessInfo(v.Id, 0, false)
				if err != nil {
					global.Log.Errorf("6GetLiveList9GetGussInfo Error:%v", err)
					continue
				}
				sTotalAmount, _ = json.Marshal(gInfo.AmountList)
				sPeopleList, _ = json.Marshal(gInfo.PeopleNumList)
				sOddsList, _ = json.Marshal(gInfo.OddsList)
				v.Pot = gInfo.Pot
				v.TotalPeople = gInfo.TotalPeople
			}

			//////////////
			slice = append(slice, &pb.GetGuessResp{
				GId:        int32(v.Id),
				QId:        int32(v.QId),
				AnchorId:   int32(v.AnchorId),
				CategoryId: int32(v.CategoryId),
				LiveId:     v.LiveId,

				EndTime: time.Unix(v.EndTime, 0).Format("2006-01-02 15:04:05"),
				Status:  int32(v.Status),
				ItemNum: int32(v.ItemNum),

				CreateTime: v.CreateTime.Format("2006-01-02 15:04:05"),
				CloseTime:  v.CloseTime.Format("2006-01-02 15:04:05"),
				SettleTime: v.SettleTime.Format("2006-01-02 15:04:05"),

				Title:       v.Title,
				Content:     v.Content,
				MatchTitle:  v.MatchTitle,
				Comp:        v.Comp,
				LiveTitle:   v.LiveTitle,
				Result:      int32(v.Result),
				Pot:         int32(v.Pot),
				PayStatus:   int32(v.PayStatus),
				TotalPeople: int32(v.TotalPeople),
				///////////////////////////////////////
				TotalAmount: string(sTotalAmount),
				PeopleNum:   string(sPeopleList),
				Odds:        string(sOddsList),
			})
		}
	} //if 不为空
	return &pb.GetGuessListResp{
		Total: n,
		Guess: slice,
	}, nil

}
